import os
import pprint
from PIL import Image, ImageDraw, ImageStat
from .utils import pull_screenshot

class Bubble:
    def __init__(self, pos, score, clickable):
        self.pos = pos
        self.score = score
        self.clickable = clickable

    def __repr__(self):
        parts = [
            f'pos={self.pos}',
            f'score={self.score}',
        ]
        if self.clickable:
            parts.append('clickable')
        body = ' '.join(parts)
        return f'<Bubble {body}>'

    def cross_area_ratio(self, other):
        p1x1, p1y1, p1x2, p1y2 = self.pos
        p2x1, p2y1, p2x2, p2y2 = other.pos if isinstance(other, Bubble) else other
        left = max(p1x1, p2x1)
        right = min(p1x2, p2x2)
        top = max(p1y1, p2y1)
        bottom = min(p1y2, p2y2)
        width = max(0, bottom - top)
        height = max(0, right - left)
        return width * height / (p1x2 - p1x1) / (p1y2 - p1y1)

class BubbleFinder:
    STD_WIDTH = 90
    RECT_BUBBLE_AREA = 0, 30, STD_WIDTH, 80
    CW, CH = 14, 14

    def __init__(self, im):
        self.im = im
        w, h = im.size
        sw = self.STD_WIDTH
        self.scale = sw / w
        sh = int(h * self.scale)
        self.sim = im.resize((sw, sh)).crop(self.RECT_BUBBLE_AREA)
        # stat = ImageStat.Stat(self.sim.convert('L'))
        # self.brightness = stat.mean[0] / 255
        self.sim.save('tmp/small.png')
        self.pixels = self.sim.load()

    def get_distance_square(self, x, y):
        cx = (self.CW - 1) / 2
        cy = (self.CH - 1) / 2
        dx, dy = x - cx, y - cy
        return dx * dx + dy * dy

    def find_bubble(self, x, y):
        # self.sim.crop((x, y, x + self.CW, y + self.CH)).save('tmp/cropped.png')
        score = 0
        tg = 0
        for j in range(self.CH):
            for i in range(self.CW):
                color = self.pixels[x + i, y + j][:3]
                sum_color = sum(color)
                rr, rg, rb = (c / sum_color for c in color)
                dist = self.get_distance_square(i, j)
                g_type = None
                rrg = 999 if rg == 0 else rr / rg
                rbg = 999 if rg == 0 else rb / rg
                if rg > .5:
                    tg += 1
                if rg < .7 and rrg <= .9 and rbg <= .95:
                    g_type = 'fore'
                    # print('x', end='')
                    # print('%.2f' % rg, end=' ')
                elif rg < .7 and rrg > .9 or rbg > .8:
                    g_type = 'back'
                    # print('.', end='')
                    # print('%.2f' % rg, end=' ')
                else:
                    # print(' ', end='')
                    # print('    ', end=' ')
                    pass
                if dist < 36:
                    score += 1 if g_type == 'fore' else -1
                # elif dist > 49:
                    # score -= 1 if g_type == 'fore' else -1
            # print()
        # print(score, tg)
        if score > 80:
            return Bubble(self.original_pos((x, y, x + self.CW, y + self.CH)), score, tg > 40)

    def find_bubbles(self):
        sw, sh = self.sim.size
        bubbles = []
        for x in range(sw - self.CW):
            for y in range(sh - self.CH):
                bubble = self.find_bubble(x, y)
                if bubble is not None:
                    for (i, item) in enumerate(bubbles):
                        if bubble.cross_area_ratio(item) > .5:
                            if bubble.score > item.score:
                                bubbles[i] = bubble
                            break
                    else:
                        bubbles.append(bubble)
        return bubbles

    def original_pos(self, pos):
        ox, oy, _, _ = self.RECT_BUBBLE_AREA
        x1, y1, x2, y2 = pos
        return ox + x1, oy + y1, ox + x2, oy + y2

    def scale_pos(self, pos, scale=1):
        return tuple(int(v * scale / self.scale) for v in pos)

if __name__ == '__main__':
    # im = pull_screenshot()
    im = Image.open('./tmp/day_self.png')
    # im = Image.open('./tmp/day_other.png')
    # im = Image.open('./tmp/night_other.png')
    bf = BubbleFinder(im)

    # day_self
    # print(bf.find_bubble(15, 13))
    # print(bf.find_bubble(36, 2))
    # print(bf.find_bubble(59, 14))
    # print(bf.find_bubble(30, 31))

    # day_other
    # print(bf.find_bubble(9, 12))
    # print(bf.find_bubble(38, 4))
    # print(bf.find_bubble(65, 30))

    # night_other
    # print(bf.find_bubble(12, 30))
    # print(bf.find_bubble(64, 23))
    # print(bf.find_bubble(36, 25))

    # pprint.pprint(bf.find_bubbles())
    bubbles = bf.find_bubbles()
    w, h = im.size
    scale = 360 / w
    sim = im.resize((360, int(h * scale)))
    draw = ImageDraw.Draw(sim)
    for (i, bubble) in enumerate(bubbles):
        print(bubble)
        pos = bf.scale_pos(bubble.pos, scale)
        draw.rectangle(pos, outline='blue' if bubble.clickable else None)
        # filename = f'tmp/cropped-{i}.png'
        # im.crop(bubble).save(filename)
        # os.system(f'imgcat {filename}')
    del draw
    filename = 'tmp/marked.png'
    sim.save(filename)
    os.system(f'imgcat {filename}')
